package eletjatek;

/**
 *
 * @author ZoZo
 */

import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import java.util.*;
import java.lang.*;

public class PaintPanel extends JPanel {
    private int x;
    private int y;
    private boolean runable;
    private ArrayList<Integer> t;
    private JDialog fChooserD = new JDialog();
    private JFileChooser fChooser = new JFileChooser();
    private GameOfLife game;

    PaintPanel(int x,int y,GameOfLife game){
        super();
        this.x=x;
        this.y=y;
        this.game=game;
        
        this.setBackground(Color.white);
        this.setMinimumSize(new Dimension(x*10,y*10));
        this.addMouseListener(new mouseApp());

        runable=false;
        t=new ArrayList<Integer>();
        nullaz();

        fChooserD.setMinimumSize(new java.awt.Dimension(400, 400));
        fChooserD.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        fChooserD.add(fChooser);
        fChooser.setFileFilter(new javax.swing.filechooser.FileFilter(){
            @Override
            public boolean accept(File f) {
            return f.getName().toLowerCase().endsWith(".cells");
            }

            @Override
            public String getDescription() {
                return "CELLS files";
            }
        });
        fChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
        fChooser.setMultiSelectionEnabled(false);
    }

    @Override
    public void paintComponent(Graphics g){
        //az élettér kirajzolása
        super.paintComponent(g);
        for(int i=1;i<y;i++) g.drawLine(0, i*10, x*10, i*10);
        for(int i=1;i<x;i++) g.drawLine(i*10, 0, i*10, y*10);
        g.setColor(Color.red);
        for(int i=0;i<y;i++)
            for(int j=0;j<x;j++)
                if(t.get(i*x+j)==1) g.fillRect(1+j*10, 1+i*10, 9, 9);
        
        if(runable){                        //ha runnable állapotban van akkor fog elkezdődni 
            vizsgalat();                    //az élettér vizsgálata, ekkor halnak el/élednek sejtek
            try {
                Thread.sleep(250);
            } catch (InterruptedException ex) {
                Logger.getLogger(PaintPanel.class.getName()).log(Level.SEVERE, null, ex);
                Fault error=new Fault("A szál alvó állapotban van és egy másik szál interrupt method-ot hajt rajta végre!");
                error.setVisible(true);
            }
        }
        this.repaint();
    }

    public void save(){
        int v = fChooser.showSaveDialog(fChooserD);
        if(v == JFileChooser.APPROVE_OPTION){
            File f = new File(fChooser.getSelectedFile().getAbsolutePath());
            if(!f.getAbsolutePath().toLowerCase().endsWith(".cells")) f = new File(f.getAbsolutePath() + ".cells");
            boolean enable = true;
            if(f.exists()){
                int response = JOptionPane.showConfirmDialog (null,"Felülírja a létező fájlt?","A fájl már létezik",
                                                              JOptionPane.OK_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE);
                if (response == JOptionPane.CANCEL_OPTION) enable = false;
            }
            if(enable){
                try{
                    ObjectOutputStream out= new ObjectOutputStream(new FileOutputStream(f));
                    out.writeObject(x);
                    out.writeObject(y);
                    out.writeObject(t);
                    out.close();
                }catch(IOException ex){
                    Fault error=new Fault("Hibás vagy megszakított I/O művelet!");
                    error.setVisible(true);
                }
            }
        }
    }

    public void load(){
        int sx,sy;

        int v = fChooser.showOpenDialog(fChooserD);
        if(v == JFileChooser.APPROVE_OPTION){
            File f = new File(fChooser.getSelectedFile().getAbsolutePath());
            if(f.getAbsolutePath().toLowerCase().endsWith(".cells")){
                boolean enable = true;
                int response = JOptionPane.showConfirmDialog (null,"Felülírja a meglevő sejttáblát?","A sejttábla már használatban van!", JOptionPane.OK_CANCEL_OPTION,JOptionPane.QUESTION_MESSAGE);
                if (response == JOptionPane.CANCEL_OPTION) enable = false;

                if(enable){
                    try {
                        ObjectInputStream in= new ObjectInputStream(new FileInputStream(f));
                        sx=(Integer)in.readObject();
                        sy=(Integer)in.readObject();
                        if(sx!=x || sy!=y){
                            this.x=sx;
                            this.y=sy;
                            this.setMinimumSize(new Dimension(x*10,y*10));
                            game.setMinimumSize(new Dimension(x*10+18,y*10+88));
                            game.setSize(x*10+18,y*10+88);
                        }
                        t.clear();
                        nullaz();
                        t = (ArrayList<Integer>)in.readObject();
                        in.close();
                    }catch(IOException ex){
                        Fault error=new Fault("Hibás vagy megszakított I/O művelet!");
                        error.setVisible(true);
                    }catch(ClassNotFoundException ex){
                        Fault error=new Fault("Nem található ilyen class!");
                        error.setVisible(true);
                    }
                }
            }
        }
    }

    public void nullaz(){
        for(int i=0;i<x*y;i++) t.add(0);
    }

    public int szomszed(int sy, int sx){
        int db=0;                                           //szomszédok darabszáma
        int seg=0;                                          //segédváltozó a az új tábla számítáásához
        ArrayList<Integer> s;                               //segédtábla

        s=new ArrayList<Integer>();                         //a segédtábla feltöltése a helyes elemekkel
        for(int i=0;i<(x+2)*(y+2);i++) s.add(0);        
        for(int i=x+3;i<((x+2)*(y+2)-(x+3));i++){
            s.set(i, t.get(seg*x+db));
            db++;
            if(db==x){
                db=0;
                i+=2;
                seg++;
            }
        }

        db=0;                                               //szomszédok számolása a segédtába segítségével
        for(int i=-1;i<2;i++)
            for(int j=-1;j<2;j++)
                if(i!=0 || j!=0)
                    if(s.get((sy+1+i)*(x+2)+(sx+1+j))==1 || s.get((sy+1+i)*(x+2)+(sx+1+j))==-1) db++;
        
        return db;
    }

    private void vizsgalat(){
        int db=0;                                                       //egy sejt szomszédjainak darabszáma

        for(int i=0;i<y;i++)                                            //elhalő sejtek megjelölése
            for(int j=0;j<x;j++)
                if(t.get(i*x+j)==1){
                        db=szomszed(i,j);
                        if(db!=2 && db!=3) t.set(i*x+j, -1);
                }
        for(int i=0;i<y;i++)                                            //éledő sejtek megjelölése
            for(int j=0;j<x;j++)
                if(t.get(i*x+j)==0){
                        db=szomszed(i,j);
                        if(db==3) t.set(i*x+j, 2);
                }
        for(int i=0;i<y;i++)                                            //a megjelöltek lekezelése
                for(int j=0;j<x;j++){
                        if(t.get(i*x+j)==-1) t.set(i*x+j, 0);
                        if(t.get(i*x+j)==2) t.set(i*x+j, 1);
                }
    }
    
    public class mouseApp extends MouseAdapter{
        @Override
        public void mousePressed(MouseEvent e){
            if(!runable){
                if(t.get((e.getX()/10)+(e.getY()/10)*x)==1) t.set((e.getX()/10)+(e.getY()/10)*x, 0);
                else t.set((e.getX()/10)+(e.getY()/10)*x, 1);
            }
        }
    }

    public void formResized(){
        if(((game.getWidth()-18)/10!=x && game.getWidth()>132) || (game.getHeight()-88)/10!=y){            
            int sx=(game.getWidth()-18)/10;
            int sy=(game.getHeight()-88)/10;
            
            if(sx>x){                               //oszlopok hozzáadása
                for(int i=1;i<y;i++)
                    for(int j=sx-x;j>0;j--)
                        t.add(i*sx-j,0);
                for(int i=0;i<sx-x;i++)
                    t.add(0);
                x=sx;
            }
            if(sy>y){                               //sorok hozzáadása
                for(int i=0;i<sy*sx-y*x;i++)
                    t.add(0);
                y=sy;
            }
            if(sx<x){                               //oszlopok törlése
                for(int i=y;i>0;i--)
                    for(int j=1;j<=x-sx;j++)
                        t.remove(i*x-j);
                x=sx;
            }
            if(sy<y){                               //sorok törlése
                for(int i=sy*sx;i<y*x;i++)
                    t.remove(sx*sy);
                y=sy;
            }
            //game.running.setText(Integer.toString(game.getWidth())+" / "+Integer.toString(game.getHeight())+" - "+Integer.toString(x)+" / "+Integer.toString(y)+" - "+Integer.toString(sx)+" / "+Integer.toString(sy)+" - "+Integer.toString(t.size()));
        }
    }
    
    
    
    
    public void setRunable(boolean b){
        this.runable=b;
    }
    
    public boolean getRunable(){
        return this.runable;
    }
    
    public int getsX(){
        return this.x;
    }
    
    public void setsX(int x){
        this.x=x;
    }
    
    public int getsY(){
        return this.y;
    }
    
    public void setsY(int y){
        this.y=y;
    }
    
    public int getTelement(int i){
        return t.get(i);
    }
    
    public void setTelement(int i,int s){
        t.set(i, s);
    }
}